home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / ArchiveLib / ArchiveLib.c next >
Encoding:
C/C++ Source or Header  |  1994-01-02  |  6.8 KB  |  190 lines  |  [TEXT/KAHL]

  1. /* Functions for archiving data to a file. A header containing the size
  2.     and the version of the data is appended, so that if the definition
  3.     of the data changes from the version stored on disk it should still be
  4.     possible to use the stored data. If you design your data so that
  5.     the default values of fields are NULL, then you will probably not
  6.     even have to be concerned with the versions of your data. For instance,
  7.     if you append new fields to a data structure, and then read in an old
  8.     version of the same data structure, then the new fields will all be NULL.
  9.     But since these are the default values for the new fields, no extra action
  10.     needs to be taken. If you really must take some action, then
  11.     you can compare the version of the returned data with the version you
  12.     requested and take appropriate action.
  13.     
  14.     Besides automating the problem of different versions of data, the archive
  15.     library could be modified to apply transformations to all of your data which
  16.     are transparent to your program. For instance, a change I am contemplating
  17.     to the archive library would apply a simple and fast compression algorithm
  18.     to the data. Some of the data structures I now archive contain long sequences
  19.     of NULLs, and it would be fairly straighforward to use run-length encoding
  20.     to reduce the size of the data. The archive library would be modified to
  21.     compress the data just before it is written to disk and decompress the data
  22.     just after it is read from disk. All these transformations can be fully
  23.     backwards compatible with older versions of data files since the archive
  24.     library stamps every item of data it writes to disk with a version number;
  25.     so data with a pre-compression version would be left untouched, while
  26.     newer data would be compressed.
  27.     
  28.     Revision History:
  29.     
  30.     93/12/15 aih
  31.     - removed scrap functions since they aren't being used and are difficult
  32.     to maintain
  33.     
  34.     91/11/15 AIH
  35.     - Uses min and max functions instead of macros
  36.     
  37.     91/05/07 AIH
  38.     - Made reading archives from a resource more robust
  39.     
  40.     91/04/02 AIH
  41.     - Added functions for reading from and writing to the scrap
  42.     
  43.     91/03/07 AIH
  44.     - Added some comments and future ideas
  45.     
  46.     91/01/21 AIH
  47.     - Added some comments describing this file
  48.     
  49.     91/01/05 Ari Halberstadt (AIH)
  50.     - Inserted this standard header in all files */
  51.  
  52. #include <string.h>
  53. #include "ArchiveLib.h"
  54. #include "MathLib.h"
  55. #include "MemoryLib.h"
  56. #include "ResourceLib.h"
  57.  
  58. /* The arsize and arversion fields of the archive header are set to these
  59.     values. Having version and size fields for the archive header allows for
  60.     future expansion of the information stored in the archive header.
  61.     Currently, both fields are ignored. */
  62. #define ARCHIVE_VERSION    (0)
  63. #define ARCHIVE_SIZE        (0)
  64.  
  65. /* the header which is written before the archived data */
  66. typedef struct {
  67.     size_t    size;            /* size of following data */
  68.     long        version;        /* version of following data */
  69.     short        arsize;        /* size of this archive (not used) */
  70.     short        arversion;    /* version of this archive (not used) */
  71. } ArchiveHdrType;
  72.  
  73. /* fill in the fields of the archive's header */
  74. static void ArchiveSet(ArchiveHdrType *hdr, size_t size, long version)
  75. {
  76.     require(size >= 0);
  77.     hdr->size = size;
  78.     hdr->version = version;
  79.     hdr->arsize = ARCHIVE_SIZE;
  80.     hdr->arversion = ARCHIVE_VERSION;
  81. }
  82.  
  83. /* Seek to the n'th archive entry in the file. The size parameter should
  84.     give the size of the data stored in the archive. This assumes that each
  85.     archive entry is the same size. */
  86. void ArchiveSeek(FileType *fp, FilePosType n, size_t size)
  87. {
  88.     require(FileValid(fp));
  89.     require(n >= 0);
  90.     require(size >= 0);
  91.     FileSeek(fp, fsFromStart, n * (size + sizeof(ArchiveHdrType)));
  92. }
  93.  
  94. /* First write an ArchiveHdrType, with the size and version fields
  95.     filled in using the given size and version. Then write the data
  96.     to the file. The file must be open for writing. */
  97. void ArchiveWrite(FileType *fp, const void *data, size_t size, long version)
  98. {
  99.     ArchiveHdrType    hdr;
  100.  
  101.     require(FileValid(fp));
  102.     require(size >= 0);
  103.     ArchiveSet(&hdr, size, version);
  104.     FileWrite(fp, sizeof(ArchiveHdrType), &hdr);
  105.     FileWrite(fp, size, data);
  106. }
  107.  
  108. /* Read the archived data from the file. The size parameter should give the
  109.     maximum amount of information which may be copied into the data pointer.
  110.     If more data are available in the archive they are ignored, and if less
  111.     data are available then the extra bytes in the returned data are set to 0.
  112.     The size parameter is set to the actual amount of data returned, and the
  113.     version parameter is set to the version field of the archive. */
  114. void ArchiveRead(FileType *fp, void *data, size_t *size, long *version)
  115. {
  116.     ArchiveHdrType    hdr;
  117.     FilePosType length = 0;
  118.     
  119.     require(FileValid(fp));
  120.     require(*size >= 0);
  121.     memclr(&hdr, sizeof(ArchiveHdrType));
  122.     (void) FileRead(fp, sizeof(ArchiveHdrType), &hdr);
  123.     length = FileRead(fp, min(hdr.size, *size), data);
  124.     if (hdr.size > *size) /* skip any remaining info */
  125.         FileSeek(fp, fsFromMark, hdr.size - *size);
  126.     if (length < *size) /* clear any extra bytes */
  127.         memclr((char *) data + length, *size - length);
  128.     *size = length; /* return size and version */
  129.     *version = hdr.version;
  130. }
  131.  
  132. /* write the data to an archive resource with the given type and ID */
  133. void ArchiveWriteRes(ResType type, short id,
  134.     const void *data, size_t size, long version)
  135. {
  136.     ArchiveHdrType hdr;
  137.     Handle archive = NULL;
  138.     
  139.     require(size >= 0);
  140.     TRY {
  141.         ArchiveSet(&hdr, size, version);
  142.         archive = HandleBegin(sizeof(ArchiveHdrType) + size);
  143.         BlockMove(&hdr, *archive, sizeof(ArchiveHdrType));
  144.         BlockMove(data, *archive + sizeof(ArchiveHdrType), size);
  145.         ResSet(archive, type, id);
  146.     } CLEANUP {
  147.         HandleEnd(archive);
  148.     } ENDTRY;
  149. }
  150.  
  151. /* same as ArchiveWriteRes, but the data are written from a handle */
  152. void ArchiveWriteResHandle(ResType type, short id,
  153.     void *data, size_t size, long version)
  154. {
  155.     SignedByte state = HandleLockHi(data);
  156.     ArchiveWriteRes(type, id, *(Handle) data, size, version);
  157.     HandleRestore(data, state);
  158. }
  159.  
  160. /* the same as ArchiveRead but gets the data from a resource */
  161. void ArchiveReadRes(ResType type, short id,
  162.     void *data, size_t *size, long *version)
  163. {
  164.     ArchiveHdrType hdr;
  165.     Handle rsrc = NULL;
  166.     size_t length = 0;
  167.         
  168.     require(*size >= 0);
  169.     rsrc = ResGet(type, id);
  170.     if (SizeResource(rsrc) >= sizeof(ArchiveHdrType)) {
  171.         BlockMove(*rsrc, &hdr, sizeof(ArchiveHdrType));
  172.         check(hdr.size == SizeResource(rsrc) - sizeof(ArchiveHdrType));
  173.         length = min(hdr.size, *size);
  174.         BlockMove(*rsrc + sizeof(ArchiveHdrType), data, length);
  175.     }
  176.     if (length < *size) /* clear any extra bytes */
  177.         memclr((char *) data + length, *size - length);
  178.     *size = length; /* return size and version */
  179.     *version = hdr.version;
  180. }
  181.  
  182. /* same as ArchiveReadRes, but the data are read into a handle */
  183. void ArchiveReadResHandle(ResType type, short id,
  184.     void *data, size_t *size, long *version)
  185. {
  186.     SignedByte state = HandleLockHi(data);
  187.     ArchiveReadRes(type, id, *(Handle) data, size, version);
  188.     HandleRestore(data, state);
  189. }
  190.